package com.hzy.ums.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.hzy.ums.domain.Member;
import com.ruoyi.common.core.domain.dto.RoleDTO;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.event.LogininforEvent;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.enums.LoginType;
import com.ruoyi.common.exception.user.UserException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.domain.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.common.utils.redis.RedisUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.hzy.ums.domain.bo.MemberLogininforBo;
import com.hzy.ums.domain.vo.MemberLogininforVo;
import com.hzy.ums.domain.MemberLogininfor;
import com.hzy.ums.mapper.MemberLogininforMapper;
import com.hzy.ums.service.IMemberLogininforService;

import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.function.Supplier;

/**
 * 会员登录记录Service业务层处理
 *
 * @author zengxin
 * @date 2023-10-19
 */
@RequiredArgsConstructor
@Service
public class MemberLogininforServiceImpl implements IMemberLogininforService {
    private final MemberLogininforMapper baseMapper;
    @Value("${user.password.maxRetryCount}")
    private Integer maxRetryCount;
    @Value("${user.password.lockTime}")
    private Integer lockTime;

    /**
     * 查询会员登录记录
     */
    @Override
    public MemberLogininforVo queryById(Long id){
        return baseMapper.selectVoById(id);
    }

    /**
     * 查询会员登录记录列表
     */
    @Override
    public TableDataInfo<MemberLogininforVo> queryPageList(MemberLogininforBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<MemberLogininfor> lqw = buildQueryWrapper(bo);
        Page<MemberLogininforVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询会员登录记录列表
     */
    @Override
    public List<MemberLogininforVo> queryList(MemberLogininforBo bo) {
        LambdaQueryWrapper<MemberLogininfor> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<MemberLogininfor> buildQueryWrapper(MemberLogininforBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<MemberLogininfor> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(bo.getPhone()), MemberLogininfor::getPhone, bo.getPhone());
        lqw.eq(bo.getMemberId() != null, MemberLogininfor::getMemberId, bo.getMemberId());
        lqw.eq(StringUtils.isNotBlank(bo.getIpaddr()), MemberLogininfor::getIpaddr, bo.getIpaddr());
        lqw.eq(StringUtils.isNotBlank(bo.getLoginLocation()), MemberLogininfor::getLoginLocation, bo.getLoginLocation());
        lqw.eq(StringUtils.isNotBlank(bo.getBrowser()), MemberLogininfor::getBrowser, bo.getBrowser());
        lqw.eq(StringUtils.isNotBlank(bo.getOs()), MemberLogininfor::getOs, bo.getOs());
        lqw.between(params.get("beginLoginTime") != null && params.get("endLoginTime") != null,
            MemberLogininfor::getLoginTime ,params.get("beginLoginTime"), params.get("endLoginTime"));
        return lqw;
    }

    /**
     * 新增会员登录记录
     */
    @Override
    public Boolean insertByBo(MemberLogininforBo bo) {
        MemberLogininfor add = BeanUtil.toBean(bo, MemberLogininfor.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改会员登录记录
     */
    @Override
    public Boolean updateByBo(MemberLogininforBo bo) {
        MemberLogininfor update = BeanUtil.toBean(bo, MemberLogininfor.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(MemberLogininfor entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除会员登录记录
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    @Override
    public void checkLogin(LoginType loginType, String username, Supplier<Boolean> supplier) {
        String errorKey = "pwd_err_cnt:" + username;
        String loginFail = "Error";
        int errorNumber = (Integer) ObjectUtil.defaultIfNull((Integer) RedisUtils.getCacheObject(errorKey), 0);
        if (errorNumber >= this.maxRetryCount) {
            this.recordLogininfor(username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), new Object[]{this.maxRetryCount, this.lockTime}));
            throw new UserException(loginType.getRetryLimitExceed(), new Object[]{this.maxRetryCount, this.lockTime});
        } else if ((Boolean)supplier.get()) {
            ++errorNumber;
            RedisUtils.setCacheObject(errorKey, errorNumber, Duration.ofMinutes((long)this.lockTime));
            if (errorNumber >= this.maxRetryCount) {
                this.recordLogininfor(username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), new Object[]{this.maxRetryCount, this.lockTime}));
                throw new UserException(loginType.getRetryLimitExceed(), new Object[]{this.maxRetryCount, this.lockTime});
            } else {
                this.recordLogininfor(username, loginFail, MessageUtils.message(loginType.getRetryLimitCount(), new Object[]{errorNumber}));
                throw new UserException(loginType.getRetryLimitCount(), new Object[]{errorNumber});
            }
        } else {
            RedisUtils.deleteObject(errorKey);
        }
    }

    @Override
    public void recordLogininfor(String username, String status, String message) {
        LogininforEvent logininforEvent = new LogininforEvent();
        logininforEvent.setUsername(username);
        logininforEvent.setStatus(status);
        logininforEvent.setMessage(message);
        logininforEvent.setRequest(ServletUtils.getRequest());
        SpringUtils.context().publishEvent(logininforEvent);
    }

    /**
     * 记录登录信息
     *
     * @param userId 用户ID
     */
    public void recordLoginInfo(Long userId) {
//        MemberLogininfor memberLogininfor = new MemberLogininfor();
//        memberLogininfor.setMemberId(userId);
//        memberLogininfor.setIpaddr(ServletUtils.getClientIP());
//        memberLogininfor.setLoginTime(DateUtils.getNowDate());
//        baseMapper.updateById(memberLogininfor);
    }

    @Override
    public LoginUser buildLoginUser(Member user) {
        LoginUser loginUser = new LoginUser();
        loginUser.setUserId(user.getId());
        loginUser.setUsername(user.getNickname());
        loginUser.setUserType(user.getLevel());
        return loginUser;
    }

}
